package com.hifinan.game;

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.*;
import javax.swing.*;

import com.hifinan.log.*;

public class SudokuTestDriver{
	//* Define basic data for this game
	static final int MINIMUM_WIDTH = 300;
	static final int MINIMUM_HEIGHT = 400;
	static final int DEFAULT_WIDTH = 300;
	static final int DEFAULT_HEIGHT = 400;
	static final int MESSAGE_DIALOG = 1;
	static final int CONFIRM_DIALOG = 2;
	// Define game level
	static final int LEVEL_EASY = 40;
	static final int LEVEL_MIDDLE = 30;
	static final int LEVEL_HARD = 20;
	static final int LEVEL_EXTREME = 10;
	// Application settings	
	static final boolean supportResize = false;
	boolean inPlaying = false;
	boolean showDebugInfo = true;

	final Button[][] mainButtons = new Button[9][9];
	int[][] sudokuInt = new int[9][9];
	ArrayList[][] availableData = new ArrayList[9][9];
	final int[] nums = {0, 1, 2, 3, 4, 5, 6, 7, 8};
	//enum DirectionKeys {KeyEvent.VK_KP_DOWN, KeyEvent.VK_KP_LEFT, KeyEvent.VK_KP_RIGHT, KeyEvent.VK_KP_UP, KeyEvent.VK_DOWN, KeyEvent.VK_LEFT, KeyEvent.VK_RIGHT, KeyEvent.VK_UP};
	//enum NumKeys {KeyEvent.VK_1, KeyEvent.VK_2, KeyEvent.VK_3, KeyEvent.VK_4, KeyEvent.VK_5, KeyEvent.VK_6, KeyEvent.VK_7, KeyEvent.VK_8, KeyEvent.VK_9, KeyEvent.VK_NUMPAD1, KeyEvent.VK_NUMPAD2, KeyEvent.VK_NUMPAD3, KeyEvent.VK_NUMPAD4, KeyEvent.VK_NUMPAD5, KeyEvent.VK_NUMPAD6, KeyEvent.VK_NUMPAD7, KeyEvent.VK_NUMPAD8, KeyEvent.VK_NUMPAD9};
	int level = LEVEL_EASY;
	// Store all displayed numbers in this arraylist
	ArrayList<Point> storeDisplay;
	int selectedX, selectedY;
	boolean confirm;

	// Interface control
	GraphicsEnvironment ge;
	GraphicsDevice gd;
	GraphicsConfiguration gc;
	Frame frame;
	MenuBar menuBar;
	Menu gameMenu;
	MenuItem gameMenuNew;
	MenuItem gameMenuPause;
	MenuItem gameMenuHistory;
	MenuItem gameMenuExit;
	Menu optionMenu;
	MenuItem optionMenuShowHelp;
	Menu helpMenu;
	MenuItem helpMenuSudokuRule;
	MenuItem helpMenuAbout;
	Panel rootPanel;
	Panel mainPanel;
	Panel buttonPanel;
	Panel numPanel;
	Panel funcPanel;
	Panel statusPanel;
	Label statusLabel;
	
	// main function
	public static void main(String[] args){
		new SudokuTestDriver().go();
	}
	void go(){
		initBasicData();
		display();
	}
	void initBasicData(){
		for(int i = 0; i < 9; i++){
			for(int j = 0; j < 9; j++){
				sudokuInt[i][j] = 0;
				mainButtons[i][j] = new Button();
			}
		}
		//storeDisplay = new ArrayList<Point>();
	}
	boolean save(){
		boolean success = false;
		ArrayList saveArrayList = new ArrayList();
		saveArrayList.add(sudokuInt);
		//System.out.println("in save() method");
		saveArrayList.add(storeDisplay);
		if(LogTestDriver.save("sudoku.sav", saveArrayList)){
			success = true;
		}
		/*
		if(LogTestDriver.save("sudoku.sav", sudokuInt)){
			if(LogTestDriver.save("sudoku.sav", storeDisplay)){
				success = true;
			}
		}
		*/
		//System.out.println(success);
		return success;
	}
	void display(){
		ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
		gd = ge.getDefaultScreenDevice();
		gc = gd.getDefaultConfiguration();
		frame = new Frame("SudokuTestDriver.java", gc);
		if(supportResize){
			frame.setMinimumSize(new Dimension(MINIMUM_WIDTH, MINIMUM_HEIGHT));
		}
		frame.addWindowListener(new WindowAdapter(){
			public void windowClosing(WindowEvent e){
				if(inPlaying){
					if(showConfirmDialog(frame, "Do you want to save and leave the game? or just leave the game?")){
						if(save()){
							frame.dispose();
							System.exit(0);
						}else{
							if(showConfirmDialog(frame, "Can't create save file, Do you want to leave?")){
								frame.dispose();
								System.exit(0);
							}
						}
					}else{
						frame.dispose();
						System.exit(0);
					}
				}else{
					frame.dispose();
					System.exit(0);
				}
			}
		});
		frame.setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
		frame.setResizable(supportResize);
		frame.setLayout(new BorderLayout());
		// set MenuBar
		menuBar = new MenuBar();
		frame.setMenuBar(menuBar);
		gameMenu = new Menu("Game", false);
		menuBar.add(gameMenu);
		gameMenuNew = new MenuItem("New game", new MenuShortcut(KeyEvent.VK_N, false));
		gameMenuNew.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				if(inPlaying){
					//System.out.println("display():" + inPlaying);
					if(showConfirmDialog(frame, "The game isn't completed, Do you want Renew?")){
						cleanGame();
						newGame();
					}
				}else{
					newGame();
				}
			}
		});
		gameMenu.add(gameMenuNew);
		gameMenuExit = new MenuItem("Exit game", new MenuShortcut(KeyEvent.VK_X, false));
		gameMenuExit.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				if(inPlaying){
					if(showConfirmDialog(frame, "Do you want to save and leave the game? or just leave the game?")){
						if(save()){
							frame.dispose();
							System.exit(0);
						}else{
							if(showConfirmDialog(frame, "Can't create save file, Do you want to leave?")){
								frame.dispose();
								System.exit(0);
							}
						}
					}else{
						frame.dispose();
						System.exit(0);
					}
				}else{
					frame.dispose();
					System.exit(0);
				}
			}
		});
		gameMenu.add(gameMenuExit);
		// set root panel
		rootPanel = new Panel(new BorderLayout());
		frame.add(rootPanel, BorderLayout.CENTER);
		// set main panel
		mainPanel = new Panel(new GridLayout(9, 9));
		
		//mainPanel.setBackground(Color.RED);
		rootPanel.add(mainPanel, BorderLayout.CENTER);
		for(final int i : nums){
			for(final int j : nums){
				mainPanel.add(mainButtons[i][j]);
				mainButtons[i][j].setBackground(mainPanel.getBackground());
				mainButtons[i][j].addActionListener(new ActionListener(){
					int iL = i;
					int jL = j;
					public void actionPerformed(ActionEvent e){
						// record the selecet label
						recordTheSelectedButton(iL, jL);
					}
				});
				mainButtons[i][j].addKeyListener(new KeyAdapter(){
					public void keyPressed(KeyEvent e){
						int i = e.getKeyCode();
						dealTheKeyEvent(i);
					}
				});
			}
		}
		// set button panel
		//Panel buttonPanel = new Panel(new FlowLayout(FlowLayout.LEFT));
		buttonPanel = new Panel(new BorderLayout());
		rootPanel.add(buttonPanel, BorderLayout.SOUTH);
		// add number button panel to button panel
		numPanel = new Panel(new GridLayout(1, 9));
		buttonPanel.add(numPanel, BorderLayout.CENTER);
		for(int i : nums){
			Button button = new Button(String.valueOf(i+1));
			button.addActionListener(new ActionListener(){
				public void actionPerformed(ActionEvent e){
					setTheSelectedButton(Integer.parseInt(((Button)(e.getSource())).getLabel()));
				}
			});
			numPanel.add(button);
		}

		funcPanel = new Panel(new BorderLayout());
		buttonPanel.add(funcPanel, BorderLayout.EAST);
		
		Button button = new Button("Erase");
		button.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				setTheSelectedButton(0);
			}
		});
		funcPanel.add(button, BorderLayout.CENTER);

		// set status panel
		statusPanel = new Panel(new GridLayout(1, 4));
		statusPanel.setBackground(Color.CYAN);
		frame.add(statusPanel, BorderLayout.SOUTH);
		statusLabel = new Label("Do something");
		statusPanel.add(statusLabel);

		newGame();
		frame.setVisible(true);
	}
	boolean readSave(){
		boolean success = false;
		try{
			File file = new File("sudoku.sav");
			if(file.exists()){
				if(showConfirmDialog(frame, "Go on playing the last game?")){
					FileInputStream fis = new FileInputStream(file);
					ObjectInputStream ois = new ObjectInputStream(fis);
					ArrayList al = (ArrayList)(ois.readObject());
					ois.close();
					sudokuInt = (int[][])(al.get(0));
					storeDisplay = (ArrayList<Point>)(al.get(1));
					success = true;
				}
				if(file.isFile()){
					System.out.println("before delete");
					file.delete();
					System.out.println("after delete");
				}
			}
		}catch(Exception e){
			e.printStackTrace();
		}
		return success;
	}

	void newGame(){
		if(!readSave()){
			int i = 1;
			while(!initSudokuArray(0, 0) && (i < 10)){
				if(showDebugInfo){
					LogTestDriver.record("sudoku.log", "inital failed " + i +" times.");
				}
				i++;
			}
			if(showDebugInfo){
				displayTheInitSudokuDataInLOG();
			}
			storeDisplay = initDisplayedPlace(level);
			cleanUnshownedNumsInSudokuArray(storeDisplay);
		}
		mapSudokuArrayToDisplayPlace(storeDisplay);
		inPlaying = true;
		setColor();
	}

	void displayTheInitSudokuDataInLOG(){
		for(int i = 0; i < 9; i++){
			StringBuilder sb = new StringBuilder();
			for(int j = 0; j < 9; j++){
				sb.append(sudokuInt[i][j] + " ");
			}
			LogTestDriver.record("sudoku.log", sb.toString());
		}
	}
	ArrayList getAvailableData(int x, int y){
		ArrayList tempArrayList = new ArrayList();
		for(int i = 1; i <= 9; i++){
			if(verifyRowInSudokuArray(x, y, i) && verifyColumnInSudokuArray(x, y, i) && verifySquareInSudokuArray(x, y, i)){
				tempArrayList.add(i);
			}
		}
		return tempArrayList;
	}
	// inital the sudoku array
	boolean initSudokuArray(int x, int y){
		boolean success = false;
		// get the available numbers in this cell
		availableData[x][y] = getAvailableData(x, y);
		// return false if there is no available numbers for this cell
		if(availableData[x][y].size() == 0){
			if(showDebugInfo){
				LogTestDriver.record("sudoku.log", "availableData at "+x+","+y+":"+sudokuInt[x][y]+availableData[x][y].toString()+"empty");
			}
			return false;
		}
		// get the number from the available data
		int index = (int)(Math.random() * availableData[x][y].size());
		// set the selected number to sudokuInt array
		sudokuInt[x][y] = (int)availableData[x][y].get(index);
		if(showDebugInfo){
			LogTestDriver.record("sudoku.log", "availableData at "+x+","+y+":"+sudokuInt[x][y]+availableData[x][y].toString());
		}
		// remove the selected number from available data
		availableData[x][y].remove(index);
		// move to next cell
		y++;
		if(y == 9){
			y = 0;
			x++;
		}
		// if over the Edge, the inital is successful
		if(x == 9){
			if(showDebugInfo){
				LogTestDriver.record("sudoku.log", "availableData at "+x+","+y+":"+sudokuInt[x-1][y]+availableData[x-1][y].toString()+"x over 8");
			}
			return true;
		}
		// recursion call initSudokuArray method, if return failed, do below things.
		while(!(success = initSudokuArray(x, y))){
			// if over the minimal edge, the inital is aborted.
			if(x == 0){
				if(showDebugInfo){
					LogTestDriver.record("sudoku.log", "availableData at "+x+","+y+":"+sudokuInt[x][y]+availableData[x][y].toString()+"x lower 0");
				}
				return false;
			}
			// move back to previous cell
			if(y == 0){
				y = 9;
				x--;
			}
			y--;
			// if no available data for current cell, go back to previous cell
			if(availableData[x][y].size() == 0){
				if(showDebugInfo){
					LogTestDriver.record("sudoku.log", "availableData at "+x+","+y+":"+sudokuInt[x][y]+availableData[x][y].toString()+"empty");
				}
				return false;
			}
			// assign data to current cell
			index = (int)(Math.random() * availableData[x][y].size());
			sudokuInt[x][y] = (int)availableData[x][y].get(index);
			if(showDebugInfo){
				LogTestDriver.record("sudoku.log", "availableData at "+x+","+y+":"+sudokuInt[x][y]+availableData[x][y].toString()+"back");
			}
			availableData[x][y].remove(index);
			// move to next cell
			y++;
			if(y == 9){
				y = 0;
				x++;
			}
			if(x == 9){
				if(showDebugInfo){
					LogTestDriver.record("sudoku.log", "availableData at "+x+","+y+":"+sudokuInt[x-1][y]+availableData[x-1][y].toString()+"x over 8");
				}
				return true;
			}
		}
		return success;
	}
	boolean verifyAllInSudokuArray(){
		boolean success = true;
		for(int i = 0; i < 9; i++){
			for(int j = 0; j < 9; j++){
				if(sudokuInt[i][j] == 0){
					return false;
				}
				if(!verifyCellInSudokuArray(i, j, sudokuInt[i][j])){
					success = false;
				}
			}
		}
		return success;
	}
	boolean verifyCellInSudokuArray(int x, int y, int num){
		boolean success = true;
		if(!(verifyRowInSudokuArray(x, y, num) && verifyColumnInSudokuArray(x, y, num) && verifySquareInSudokuArray(x, y, num))){
			success = false;
		}
		return success;
	}
	boolean verifyRowInSudokuArray(int x, int y, int num){
		boolean success = true;
		for(int yy : nums){
			if(yy != y){
				if(sudokuInt[x][yy] == num){
					success = false;
				}
			}
		}
		return success;
	}
	boolean verifyColumnInSudokuArray(int x, int y, int num){
		boolean success = true;
		for(int xx : nums){
			if(xx != x){
				if(sudokuInt[xx][y] == num){
					success = false;
				}
			}
		}
		return success;
	}
	boolean verifySquareInSudokuArray(int x, int y, int num){
		boolean success = true;
		int xx = (int)(x / 3) * 3;
		int yy = (int)(y / 3) * 3;
		for(int i = xx; i < xx + 3; i++){
			for(int j = yy; j < yy + 3; j++){
				if(!((i == x) && (j == y))){
					if(sudokuInt[i][j] == num){
						success = false;
					}
				}
			}
		}
		return success;
	}
	boolean showConfirmDialog(Frame aFrame, String message){
		confirm = false;
		final Dialog dialog = new Dialog(aFrame, true);
		dialog.setUndecorated(false);
		Label label = new Label(message);
		dialog.add(label, BorderLayout.CENTER);
		Panel buttonPanel = new Panel(new FlowLayout());
		dialog.add(buttonPanel, BorderLayout.SOUTH);
		Button buttonYES = new Button("Yes");
		Button buttonNO = new Button("No");
		buttonYES.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				confirm = true;
				dialog.dispose();
			}
		});
		buttonNO.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				confirm = false;
				dialog.dispose();
			}
		});
		buttonPanel.add(buttonYES);
		buttonPanel.add(buttonNO);
		dialog.setLocationRelativeTo(aFrame);
		dialog.pack();
		dialog.setVisible(true);
		return confirm;
	}
	void moveFocus(int x, int y){
		selectedX += x;
		selectedY += y;
		if(selectedX > 8){
			selectedX = 0;
		}
		if(selectedX < 0){
			selectedX = 8;
		}
		if(selectedY > 8){
			selectedY = 0;
		}
		if(selectedY < 0){
			selectedY = 8;
		}
		setFocus();
	}
	void dealTheKeyEvent(int i){
		switch(i){
			case KeyEvent.VK_KP_UP: moveFocus(-1, 0); break;
			case KeyEvent.VK_KP_DOWN: moveFocus(1, 0); break;
			case KeyEvent.VK_KP_LEFT: moveFocus(0, -1); break;
			case KeyEvent.VK_KP_RIGHT: moveFocus(0, 1); break;
			case KeyEvent.VK_UP: moveFocus(-1, 0); break;
			case KeyEvent.VK_DOWN: moveFocus(1, 0); break;
			case KeyEvent.VK_LEFT: moveFocus(0, -1); break;
			case KeyEvent.VK_RIGHT: moveFocus(0, 1); break;
			case KeyEvent.VK_0: setTheSelectedButton(0); break;
			case KeyEvent.VK_1: setTheSelectedButton(1); break;
			case KeyEvent.VK_2: setTheSelectedButton(2); break;
			case KeyEvent.VK_3: setTheSelectedButton(3); break;
			case KeyEvent.VK_4: setTheSelectedButton(4); break;
			case KeyEvent.VK_5: setTheSelectedButton(5); break;
			case KeyEvent.VK_6: setTheSelectedButton(6); break;
			case KeyEvent.VK_7: setTheSelectedButton(7); break;
			case KeyEvent.VK_8: setTheSelectedButton(8); break;
			case KeyEvent.VK_9: setTheSelectedButton(9); break;
    			case KeyEvent.VK_NUMPAD0: setTheSelectedButton(0); break;
    			case KeyEvent.VK_NUMPAD1: setTheSelectedButton(1); break;
    			case KeyEvent.VK_NUMPAD2: setTheSelectedButton(2); break;
    			case KeyEvent.VK_NUMPAD3: setTheSelectedButton(3); break;
    			case KeyEvent.VK_NUMPAD4: setTheSelectedButton(4); break;
    			case KeyEvent.VK_NUMPAD5: setTheSelectedButton(5); break;
    			case KeyEvent.VK_NUMPAD6: setTheSelectedButton(6); break;
    			case KeyEvent.VK_NUMPAD7: setTheSelectedButton(7); break;
    			case KeyEvent.VK_NUMPAD8: setTheSelectedButton(8); break;
    			case KeyEvent.VK_NUMPAD9: setTheSelectedButton(9); break;
			case KeyEvent.VK_BACK_SPACE: setTheSelectedButton(0); break;
			case KeyEvent.VK_DELETE: setTheSelectedButton(0); break;
		}
	}
	void cleanUnshownedNumsInSudokuArray(ArrayList<Point> displayPlace){
		for(int i : nums){
			for(int j : nums){
				if(!displayPlace.contains(new Point(i, j))){
					sudokuInt[i][j] = 0;
				}
			}
		}
	}
	void setColor(){
		setRowColor(Color.CYAN);
		setColumnColor(Color.CYAN);
		setSquareColor(Color.LIGHT_GRAY, Color.GRAY);
	}
	void cleanColor(){
		Color c = mainPanel.getBackground();
		setRowColor(c);
		setColumnColor(c);
		setSquareColor(c);
		/* inefficient method to clean the color
		for(int i = 0; i < 9; i++){
			for(int j = 0; j < 9; j++){
				mainButtons[i][j].setBackground(mainPanel.getBackground());
			}
		}
		*/
	}
	void setRowColor(Color c){
		for(int i = 0; i < 9; i++){
		//	if(i != selectedX){
				mainButtons[i][selectedY].setBackground(c);
		//	}
		}
	}
	void setColumnColor(Color c){
		for(int j = 0; j < 9; j++){
			if(j != selectedY){
				mainButtons[selectedX][j].setBackground(c);
			}
		}
	}
	void setSquareColor(Color c){
//		System.out.println("selectedX:"+selectedX+" selectedY:"+selectedY);
		for(int i = (int)(selectedX / 3) * 3; i < (int)(selectedX / 3) * 3 + 3; i++){
			if(i != selectedX){
				for(int j = (int)(selectedY / 3) * 3; j < (int)(selectedY / 3) * 3 + 3; j++){
					if(j != selectedY){
						mainButtons[i][j].setBackground(c);
					}
				}
			}
		}
	}
	void setSquareColor(Color c, Color ac){
		Color tempC;
		for(int i = 0; i < 3; i++){
			for(int j = 0; j < 3; j++){
				for(int x = i * 3; x < i * 3 + 3; x++){
					for(int y = j * 3; y < j * 3 + 3; y++){
						if(x != selectedX){
							if(y != selectedY){
								mainButtons[x][y].setBackground(c);
							}
						}
					}
				}
				tempC = c;
				c = ac;
				ac = tempC;
			}
		}
	}
	void cleanGame(){
		storeDisplay = null;
		for(int i = 0; i < 9; i++){
			for(int j = 0; j < 9; j++){
				sudokuInt[i][j] = 0;
				mainButtons[i][j].setLabel("");
			}
		}
		inPlaying = false;
	}
	void mapSudokuArrayToDisplayPlace(ArrayList<Point> displayPlace){
		Font newFont = getNewFont();
		//System.out.println("font.getName:"+font.getName()+" font.getSize:"+font.getSize());
		for(int i = 0; i < 9; i++){
			for(int j = 0; j < 9; j++){
				if(sudokuInt[i][j] != 0){
					if(displayPlace.contains(new Point(i, j))){
						mainButtons[i][j].setForeground(Color.RED);
					}else{
						mainButtons[i][j].setForeground(Color.BLACK);
					}
					mainButtons[i][j].setLabel(sudokuInt[i][j] + "");
					mainButtons[i][j].setFont(newFont);
				}
			}
						
		}
	}
	// inital display place, the returned arraylist contains the coordinate
	ArrayList<Point> initDisplayedPlace(int level){
		if(level < 1){
			if(showDebugInfo){
				LogTestDriver.record("sudoku.log", "The count of numbers are too small, please increase the count");
			}
			return null;
		}
		if(level > 81){
			if(showDebugInfo){
				LogTestDriver.record("sudoku.log", "The count of numbers are too big, please decrease the count");
			}
			return null;
		}
		int countInSquare = (int)(level / 9);
		int remainder = level % 9;
		ArrayList<Point> selectedPlaceInSquare = new ArrayList<Point>();
		if(countInSquare > 0){
			for(int i = 0; i < 3; i++){
				for(int j = 0; j < 3; j++){
					ArrayList<Point> selectedPlaceInMiniSquare = new ArrayList<Point>();
					while(selectedPlaceInMiniSquare.size() < countInSquare){
						int x = i * 3 + (int)(Math.random() * 3);
						int y = j * 3 + (int)(Math.random() * 3);
						Point point = new Point(x, y);
						if(!selectedPlaceInMiniSquare.contains(point)){
							selectedPlaceInMiniSquare.add(point);
							selectedPlaceInSquare.add(point);
						}
					}
				}
			}
		}
		ArrayList<Point> selectedRemainderInBigSquare = new ArrayList<Point>();
		if(remainder > 0){
			int i, j;
			Point point;
			while(selectedRemainderInBigSquare.size() < remainder){
				i = (int)(Math.random() * 3);
				j = (int)(Math.random() * 3);
				point = new Point(i, j);
				if(!selectedRemainderInBigSquare.contains(point)){
					selectedRemainderInBigSquare.add(point);
					do{
						int x = i * 3 + (int)(Math.random() * 3);
						int y = j * 3 + (int)(Math.random() * 3);
						point = new Point(x, y);
					}while(selectedPlaceInSquare.contains(point));
					selectedPlaceInSquare.add(point);
				}
			}
		}
		return selectedPlaceInSquare;
	}

	// deal the selected label
	void recordTheSelectedButton(int i, int j){
		//System.out.println(i + " " + j + ":"+sudokuInt[i][j]);
		//cleanColor();
		selectedX = i;
		selectedY = j;
		setColor();
	}
	void setFocus(){
		mainButtons[selectedX][selectedY].requestFocusInWindow();
		setColor();
	}
	//void setTheSelectedLabel(String s){
	void setTheSelectedButton(int i){
		Font newFont = getNewFont();
		if(!storeDisplay.contains(new Point(selectedX, selectedY))){
			mainButtons[selectedX][selectedY].setFont(newFont);
			mainButtons[selectedX][selectedY].setForeground(Color.BLACK);
			if(i != 0){
				mainButtons[selectedX][selectedY].setLabel(String.valueOf(i));
			}else{
				mainButtons[selectedX][selectedY].setLabel("");
			}
			sudokuInt[selectedX][selectedY] = i;
		}
		if(verifyAllInSudokuArray()){
					JOptionPane.showMessageDialog(frame, "Congratulat!! You have Done!", "SudokuGame", JOptionPane.PLAIN_MESSAGE);
		}
		setFocus();
	}
	Font getNewFont(){
		//Font font = mainPanel.getFont();
		Rectangle rectangle = frame.getBounds();
		double frameSize = Math.min(rectangle.getHeight(), rectangle.getWidth());
		Font newFont = new Font(Font.DIALOG, Font.BOLD, (int)(frameSize/10));
		return newFont;
	}
	void setTheSelectedButton(){
		setTheSelectedButton(0);
	}
	void showMessageDialog(Frame aFrame, String message){
		final Dialog dialog = new Dialog(aFrame, true);
		dialog.setUndecorated(true);
		Label label = new Label(message);
		dialog.add(label, BorderLayout.CENTER);
		Panel buttonPanel = new Panel(new FlowLayout());
		dialog.add(buttonPanel, BorderLayout.SOUTH);
		Button buttonOK = new Button("OK");
		buttonOK.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				dialog.setVisible(false);
			}
		});
		buttonPanel.add(buttonOK);
		dialog.setVisible(true);
	}


/*	void setNumInButton(ArrayList<String> displayNumArrayList){
		int x, y;
		for(String str : displayNumArrayList){
			String[] strs = str.split(" ");
			// assert begin
			int i = 0;
			for(String tempStr: strs){
				System.out.println(i++ + ":" + tempStr);
			}
			x = y = 0;
			// assert end
			x = Integer.valueOf(strs[0]);
			y = Integer.valueOf(strs[1]);
			Point point = new Point(x, y);
			int num = (int)(Math.random()*9) + 1;
			while(!verifyCell(point, num)){
				num = (int)(Math.random()*9) + 1;
				System.out.println(num+"");
				try{
					System.out.println(new BufferedReader(new InputStreamReader(System.in)).readLine());
				}catch(IOException e){
					e.printStackTrace();
				}
			}
			mainInt[x][y] = num;
			mainButtons[x][y].setLabel(num + "");
			mainButtons[x][y].setEnabled(false);
		}
	}
*/
	//////////////////////////////////////////////////////////////
	void frameTest(){
		//Frame frame = new Frame();
		// The method getLocalGraphicsEnvironment() return a class's instance,
		// this class extend the abstract class GraphicsEnvironment and implement
		// all the methods extended form abstract class GraphicsEnvironment.
		GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
		// Test assert method
		assert (true) : "assert is true, go ahead";
		// The method getScreenDevices() return a class's instance *array*,
		// this class extend the abstract class GraphicsDevice and implement
		// all the methods extended form abstract class GraphicsDevice.
		GraphicsDevice[] gds = ge.getScreenDevices();
		System.out.println(gds.length);
		for(final GraphicsDevice gd : gds){
			System.out.println(gd.toString());
			// list all types of graphic device
			System.out.println("GraphicsDevice's types:\n\rIMAGE_BUFFER: \t" + gd.TYPE_IMAGE_BUFFER +
					"\n\rPRINTER: \t" + gd.TYPE_PRINTER +
					"\n\rSCREEN: \t" + gd.TYPE_RASTER_SCREEN);
			System.out.println("this graphics type: \t" + gd.getType());
			System.out.println("is full screen supported: \t" + gd.isFullScreenSupported());
			System.out.println("is display change supported: \t" + gd.isDisplayChangeSupported());
			Window window = gd.getFullScreenWindow();
			if(window != null){
				System.out.println("get full screen window: \t" + window.toString());
			}else{
				System.out.println("the screen is not in full screen models.");
			}
			// create a frame on this graphic device at default configuration model
			final Frame frame = new Frame("SudokuTestDriver.java", gd.getDefaultConfiguration());
			frame.setResizable(false);
			// remove the title bar from this frame
			frame.setUndecorated(true);
			// set the frame to full screen mode. after this operation,
			// we can change this graphic device's display mode.
			gd.setFullScreenWindow(frame);
			// output this graphic device's property.
			System.out.println("is full screen supported: \t" + gd.isFullScreenSupported());
			System.out.println("is display change supported: \t" + gd.isDisplayChangeSupported());
			window = gd.getFullScreenWindow();
			if(window != null){
				System.out.println("get full screen window: \t" + window.toString());
			}else{
				System.out.println("the screen is not in full screen models.");
			}
			Panel panel = new Panel();
			frame.add(panel);
			Button button = new Button("call setFullScreenWindow method");
			button.addActionListener(new ActionListener(){
				public void actionPerformed(ActionEvent e){
					gd.setFullScreenWindow(frame);
				}
			});
			Button button1 = new Button("Exit");
			button1.addActionListener(new ActionListener(){
				public void actionPerformed(ActionEvent e){
					System.exit(0);
				}
			});
			panel.add(button);
			panel.add(button1);
			// The method getConfigurations() return a class's instance *array*,
			// this class extend the abstract class GraphicsConfiguration and implement
			// all the methods extended form abstract class GraphicsConfiguration.
			GraphicsConfiguration[] gcs = gd.getConfigurations();
			for(GraphicsConfiguration gc : gcs){
				System.out.println(gc.toString());
			}
			DisplayMode[] dms = gd.getDisplayModes();
			System.out.println(dms.length);
			for(final DisplayMode dm : dms){
				int width = dm.getWidth();
				int height = dm.getHeight();
				int bitDepth = dm.getBitDepth();
				int refreshRate = dm.getRefreshRate();
				String s = width + "X" + height + " " + bitDepth + "bit " + refreshRate + "Hz";
				//System.out.println(s);
				if((width > height) && (width > 799)){
					Button tempButton = new Button(s);
					tempButton.addActionListener(new ActionListener(){
						public void actionPerformed(ActionEvent e){
							gd.setDisplayMode(dm);
						}
					});
					panel.add(tempButton);
				}
			}
			Button button2 = new Button("return the default display mode");
			final DisplayMode oldDisplayMode = gd.getDisplayMode();
			button2.addActionListener(new ActionListener(){
				public void actionPerformed(ActionEvent e){
					gd.setDisplayMode(oldDisplayMode);
				}
			});
			panel.add(button2);
			final TextField textField = new TextField(30);
			textField.enableInputMethods(true);
			panel.add(textField);
			final Button button3 = new Button("disable input");
			button3.addActionListener(new ActionListener(){
				public void actionPerformed(ActionEvent e){
					if(button3.getLabel().compareTo("disable input") == 0){
						textField.enableInputMethods(false);
						button3.setLabel("enable input");
					}else{
						textField.enableInputMethods(true);
						button3.setLabel("disable input");
					}
				}
			});
			panel.add(button3);
			frame.setVisible(true);
		}
	}
}
	class Point implements Serializable{
		int x, y;
		public Point(int xx, int yy){
			x = xx;
			y = yy;
		}
		public int hashCode(){
			return x + y;
		}
		public boolean equals(Object o){
			boolean success = false;
			Point p = (Point)o;
			if((p.x == x) && (p.y == y)){
				success = true;
			}
			return success;
		}
	}

